package org.linlinjava.litemall.db.service;

import com.github.pagehelper.PageHelper;
import org.linlinjava.litemall.db.dao.LitemallOrderMapper;
import org.linlinjava.litemall.db.dao.LitemallShopBalanceLogMapper;
import org.linlinjava.litemall.db.dao.LitemallShopSettingMapper;
import org.linlinjava.litemall.db.dao.LitemallUserBalanceLogMapper;
import org.linlinjava.litemall.db.dao.LitemallUserBalanceMapper;
import org.linlinjava.litemall.db.dao.OrderMapper;
import org.linlinjava.litemall.db.domain.LitemallAdmin;
import org.linlinjava.litemall.db.domain.LitemallOrder;
import org.linlinjava.litemall.db.domain.LitemallOrderExample;
import org.linlinjava.litemall.db.domain.LitemallShopBalanceLog;
import org.linlinjava.litemall.db.domain.LitemallShopSetting;
import org.linlinjava.litemall.db.domain.LitemallUserBalance;
import org.linlinjava.litemall.db.domain.LitemallUserBalanceLog;
import org.linlinjava.litemall.db.util.OrderUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

@Service
public class LitemallOrderService {
    @Resource
    private LitemallOrderMapper litemallOrderMapper;
    @Resource
    private OrderMapper orderMapper;
    @Autowired
    private LitemallUserBalanceMapper userbalanceMapper;
    @Autowired
    private LitemallShopBalanceLogMapper shopBalanceLogMapper;
    @Autowired
    private LitemallShopSettingMapper shopSettingMapper;

    public int add(LitemallOrder order) {
        order.setAddTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        return litemallOrderMapper.insertSelective(order);
    }

    public int count(Integer userId) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andUserIdEqualTo(userId).andDeletedEqualTo(false);
        return (int) litemallOrderMapper.countByExample(example);
    }

    public LitemallOrder findById(Integer orderId) {
        return litemallOrderMapper.selectByPrimaryKey(orderId);
    }

    public LitemallOrder findById(Integer userId, Integer orderId) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andIdEqualTo(orderId).andUserIdEqualTo(userId).andDeletedEqualTo(false);
        return litemallOrderMapper.selectOneByExample(example);
    }

    private String getRandomNum(Integer num) {
        String base = "0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < num; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public int countByOrderSn(Integer userId, String orderSn) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andUserIdEqualTo(userId).andOrderSnEqualTo(orderSn).andDeletedEqualTo(false);
        return (int) litemallOrderMapper.countByExample(example);
    }

    // TODO 这里应该产生一个唯一的订单，但是实际上这里仍然存在两个订单相同的可能性
    public String generateOrderSn(Integer userId) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMdd");
        String now = df.format(LocalDate.now());
        String orderSn = now + getRandomNum(6);
        while (countByOrderSn(userId, orderSn) != 0) {
            orderSn = now + getRandomNum(6);
        }
        return orderSn;
    }

    public List<LitemallOrder> queryByOrderStatus(Integer userId, List<Short> orderStatus, Integer page, Integer limit, String sort, String order) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.setOrderByClause(LitemallOrder.Column.addTime.desc());
        LitemallOrderExample.Criteria criteria = example.or();
        criteria.andUserIdEqualTo(userId);
        if (orderStatus != null) {
            criteria.andOrderStatusIn(orderStatus);
        }
        criteria.andDeletedEqualTo(false);
        if (!StringUtils.isEmpty(sort) && !StringUtils.isEmpty(order)) {
            example.setOrderByClause(sort + " " + order);
        }

        PageHelper.startPage(page, limit);
        return litemallOrderMapper.selectByExample(example);
    }
    
    public List<LitemallOrder> queryByShopOrderList(Integer shopId, List<Short> orderStatus, Integer page, Integer limit, String sort, String order) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.setOrderByClause(LitemallOrder.Column.addTime.desc());
        LitemallOrderExample.Criteria criteria = example.or();
        //criteria.andUserIdEqualTo(shopId);
        criteria.andShopIdEqualTo(shopId);
        if (orderStatus != null) {
            criteria.andOrderStatusIn(orderStatus);
        }
        criteria.andDeletedEqualTo(false);
        if (!StringUtils.isEmpty(sort) && !StringUtils.isEmpty(order)) {
            example.setOrderByClause(sort + " " + order);
        }
        
        PageHelper.startPage(page, limit);
        return litemallOrderMapper.queryByShopOrderList(example);
    }

    public List<LitemallOrder> querySelective(Integer userId, String orderSn, String mobile, LocalDateTime start, LocalDateTime end, List<Short> orderStatusArray, Integer page, Integer limit, String sort, String order) {
        LitemallOrderExample example = new LitemallOrderExample();
        LitemallOrderExample.Criteria criteria = example.createCriteria();

        if (userId != null) {
            criteria.andUserIdEqualTo(userId);
        }
        if (!StringUtils.isEmpty(orderSn)) {
            criteria.andOrderSnEqualTo(orderSn);
        }
        if(!StringUtils.isEmpty(mobile)) {
        	criteria.andMobileLike("%"+ mobile + "%");
        }
        if(start != null){
            criteria.andAddTimeGreaterThanOrEqualTo(start);
        }
        if(end != null){
            criteria.andAddTimeLessThanOrEqualTo(end);
        }
        if (orderStatusArray != null && orderStatusArray.size() != 0) {
            criteria.andOrderStatusIn(orderStatusArray);
        }
        criteria.andDeletedEqualTo(false);

        if (!StringUtils.isEmpty(sort) && !StringUtils.isEmpty(order)) {
            example.setOrderByClause(sort + " " + order);
        }

        PageHelper.startPage(page, limit);
        return litemallOrderMapper.selectByExample(example);
    }
    
    public List<LitemallOrder> Merchant_querySelective(LitemallAdmin admin, Integer userId, String orderSn, String mobile, LocalDateTime start, LocalDateTime end, List<Short> orderStatusArray, Integer page, Integer limit, String sort, String order) {
        LitemallOrderExample example = new LitemallOrderExample();
        LitemallOrderExample.Criteria criteria = example.createCriteria();
        if(admin == null) {
        	return null;
        }
        	criteria.andShopIdEqualTo(admin.getShopId());
        if (userId != null) {
            criteria.andUserIdEqualTo(userId);
        }
        if (!StringUtils.isEmpty(orderSn)) {
            criteria.andOrderSnEqualTo(orderSn);
        }
        if(!StringUtils.isEmpty(mobile)) {
        	criteria.andMobileLike("%"+ mobile + "%");
        }
        if(start != null){
            criteria.andAddTimeGreaterThanOrEqualTo(start);
        }
        if(end != null){
            criteria.andAddTimeLessThanOrEqualTo(end);
        }
        if (orderStatusArray != null && orderStatusArray.size() != 0) {
            criteria.andOrderStatusIn(orderStatusArray);
        }
        criteria.andDeletedEqualTo(false);

        if (!StringUtils.isEmpty(sort) && !StringUtils.isEmpty(order)) {
            example.setOrderByClause(sort + " " + order);
        }

        PageHelper.startPage(page, limit);
        return litemallOrderMapper.selectByExample(example);
    }

    public int updateWithOptimisticLocker(LitemallOrder order) {
        LocalDateTime preUpdateTime = order.getUpdateTime();
        order.setUpdateTime(LocalDateTime.now());
        return orderMapper.updateWithOptimisticLocker(preUpdateTime, order);
    }
    
    
    /**
     * 修改订单状态、并添加商家收入记录
     * @param order
     * @return
     */
    @Transactional
    public int updateOrderStatus(LitemallOrder order) {
    	LocalDateTime preUpdateTime = order.getUpdateTime();
        order.setUpdateTime(LocalDateTime.now());
    	int result = 0;
    	if(orderMapper.updateWithOptimisticLocker(preUpdateTime, order) == 1) {
    		LitemallShopBalanceLog slg = shopBalanceLogMapper.getOneByOrderId(order.getId());
    		if(slg != null) {
    			return 1;
    		}
    		LitemallShopSetting shopSetting = shopSettingMapper.getOneByShopId(order.getShopId());
    		//添加商家收入记录
    		LitemallShopBalanceLog record = new LitemallShopBalanceLog();
    		record.setUpdateTime(LocalDateTime.now());
    		record.setAddTime(LocalDateTime.now());
    		record.setStatus(0);//0待入账 1已入账
    		record.setShopId(order.getShopId());
    		record.setOrderId(order.getId());
    		record.setOrderPrice(order.getActualPrice());//订单用户最终支付金额（订单金额-优惠金额）
    		record.setRate(shopSetting.getRate());
    		record.setUpstairsPrice(order.getDeliverymoney());//上楼费用
    		BigDecimal rate = new BigDecimal(shopSetting.getRate());
    		BigDecimal ratePrice = order.getActualPrice().multiply(rate);
    		BigDecimal num = new BigDecimal(100);
    		BigDecimal actualRatePrice = ratePrice.divide(num);
    		record.setRatePrice(actualRatePrice);
    		record.setDeliveryman(shopSetting.getDeliveryStatus());
    		if(shopSetting.getDeliveryStatus() == 1) {//平台配送 配送费按 15%收取 不足3元按 3元收取
    			/*
    			BigDecimal deliveryRate = new BigDecimal(15);
    			BigDecimal deliverycost = order.getOrderPrice().multiply(deliveryRate).divide(num);*/
    			record.setDeliverycost(order.getDeliverycost());
    			//商家最终收入 订单金额 - 平台费用 - 跑腿费用 - 上楼费用
    			record.setActualPrice(order.getActualPrice().subtract(actualRatePrice).subtract(order.getDeliverycost()).subtract(order.getDeliverymoney()));
    		}else {//商家自己配送 平台收取 0费用
    			//商家最终收入 订单金额 - 平台费用
    			
    			record.setActualPrice(order.getActualPrice().subtract(actualRatePrice).subtract(order.getDeliverymoney()));
    			record.setDeliverycost(new BigDecimal(0));
    		}
    		result = shopBalanceLogMapper.insert(record);
    	}
    	
    	return result;
    }

    public void deleteById(Integer id) {
        litemallOrderMapper.logicalDeleteByPrimaryKey(id);
    }

    public int count() {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andDeletedEqualTo(false);
        return (int) litemallOrderMapper.countByExample(example);
    }

    public List<LitemallOrder> queryUnpaid(int minutes) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andOrderStatusEqualTo(OrderUtil.STATUS_CREATE).andDeletedEqualTo(false);
        return litemallOrderMapper.selectByExample(example);
    }

    public List<LitemallOrder> queryUnconfirm(int days) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expired = now.minusDays(days);
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andOrderStatusEqualTo(OrderUtil.STATUS_SHIP).andShipTimeLessThan(expired).andDeletedEqualTo(false);
        return litemallOrderMapper.selectByExample(example);
    }

    public LitemallOrder findBySn(String orderSn) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andOrderSnEqualTo(orderSn).andDeletedEqualTo(false);
        return litemallOrderMapper.selectOneByExample(example);
    }

    public Map<Object, Object> orderInfo(Integer userId,Integer shopId) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andUserIdEqualTo(userId).andDeletedEqualTo(false);
        List<LitemallOrder> orders = litemallOrderMapper.selectByExampleSelective(example, LitemallOrder.Column.orderStatus, LitemallOrder.Column.comments);

        int unpaid = 0;
        int unship = 0;
        int unrecv = 0;
        int uncomment = 0;
        for (LitemallOrder order : orders) {
            if (OrderUtil.isCreateStatus(order)) {
                unpaid++;
            } else if (OrderUtil.isPayStatus(order)) {
                unship++;
            } else if (OrderUtil.isShipStatus(order)) {
                unrecv++;
            } else if (OrderUtil.isConfirmStatus(order) || OrderUtil.isAutoConfirmStatus(order)) {
                uncomment += order.getComments();
            } else {
                // do nothing
            }
        }
        long orderCount = 0;
        BigDecimal balance = new BigDecimal(0);
        if(shopId != null) {
        	long shopOrderCount = litemallOrderMapper.selectByShoIdOrderCount(shopId);
        	orderCount = shopOrderCount;
        	//只有门店管理者在小程序端有显示 余额
        	//查询用户余额
        	LitemallUserBalance ub = userbalanceMapper.getUserBalance(shopId);
        	if(ub != null) {
        		balance = ub.getBalance();
        	}
        }
        
        Map<Object, Object> orderInfo = new HashMap<Object, Object>();
        orderInfo.put("unpaid", unpaid);
        orderInfo.put("unship", unship);
        orderInfo.put("unrecv", unrecv);
        orderInfo.put("uncomment", uncomment);
        orderInfo.put("orderCount", orderCount);
        orderInfo.put("balance", balance);
        return orderInfo;

    }
    
    public Map<Object, Object> ShopOrderInfo(Integer shopId) {
    	/*
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andShopIdEqualTo(shopId).andDeletedEqualTo(false);
        List<LitemallOrder> orders = litemallOrderMapper.selectByExampleSelective(example, LitemallOrder.Column.orderStatus, LitemallOrder.Column.comments);

        int unpaid = 0;
        int unship = 0;
        int unrecv = 0;
        int uncomment = 0;
        for (LitemallOrder order : orders) {
            if (OrderUtil.isCreateStatus(order)) {
                unpaid++;
            } else if (OrderUtil.isPayStatus(order)) {
                unship++;
            } else if (OrderUtil.isShipStatus(order)) {
                unrecv++;
            } else if (OrderUtil.isConfirmStatus(order) || OrderUtil.isAutoConfirmStatus(order)) {
                uncomment += order.getComments();
            } else {
                // do nothing
            }
        }*/
        long orderCount = 0;
        BigDecimal balance = new BigDecimal(0);
        if(shopId != null) {
        	long shopOrderCount = litemallOrderMapper.selectByShoIdOrderCount(shopId);
        	orderCount = shopOrderCount;
        	//只有门店管理者在小程序端有显示 余额
        	//查询用户余额
        	/*
        	LitemallUserBalance ub = userbalanceMapper.getUserBalance(shopId);
        	if(ub != null) {
        		balance = ub.getBalance();
        	}*/
        }
        
        Map<Object, Object> orderInfo = new HashMap<Object, Object>();
        /*
        orderInfo.put("unpaid", unpaid);
        orderInfo.put("unship", unship);
        orderInfo.put("unrecv", unrecv);
        orderInfo.put("uncomment", uncomment);*/
        orderInfo.put("orderCount", 88);
        orderInfo.put("balance", 800);
        return orderInfo;

    }
    
    public Map<Object, Object> orderInfo(Integer userId) {
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andUserIdEqualTo(userId).andDeletedEqualTo(false);
        List<LitemallOrder> orders = litemallOrderMapper.selectByExampleSelective(example, LitemallOrder.Column.orderStatus, LitemallOrder.Column.comments);
        Map<Object, Object> orderInfo = new HashMap<Object, Object>();
        orderInfo.put("activity", orders.size());
        return orderInfo;
    }
    
    public List<LitemallOrder> ReminderOrderInfo(Integer userId) {
        return litemallOrderMapper.selectByTodayReminderOrder(userId);
    }

    public List<LitemallOrder> queryComment(int days) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expired = now.minusDays(days);
        LitemallOrderExample example = new LitemallOrderExample();
        example.or().andCommentsGreaterThan((short) 0).andConfirmTimeLessThan(expired).andDeletedEqualTo(false);
        return litemallOrderMapper.selectByExample(example);
    }

    public void updateAftersaleStatus(Integer orderId, Short statusReject) {
        LitemallOrder order = new LitemallOrder();
        order.setId(orderId);
        order.setAftersaleStatus(statusReject);
        order.setUpdateTime(LocalDateTime.now());
        litemallOrderMapper.updateByPrimaryKeySelective(order);
    }
    
    public List<LitemallOrder> selectByTodayOrder(Integer shopId,Integer payType){
    	return litemallOrderMapper.selectByTodayOrder(shopId,payType);
    }
    
    public List<LitemallOrder> selectByYesterdayOrder(Integer shopId){
    	return litemallOrderMapper.selectByYesterdayOrder(shopId);
    }
    
    public List<LitemallOrder> getMerchantStatistics(Integer ShopId){
        LitemallOrderExample example = new LitemallOrderExample();
        LitemallOrderExample.Criteria criteria = example.createCriteria();
        if(ShopId == null) {
        	return null;
        }
        criteria.andShopIdEqualTo(ShopId);
        
        criteria.andDeletedEqualTo(false);

        return litemallOrderMapper.selectByExample(example);
    }
    
    public List<LitemallOrder> selectByExampleByorderStatus(String orderStatusArray){
    	return litemallOrderMapper.selectByExampleByorderStatus(orderStatusArray);
    }

	public List<LitemallOrder> listTakeOutOrder(String orderStatusArray) {
		return litemallOrderMapper.selectByExampleByorderStatusss(orderStatusArray);
	}
	
	public void buildOrder(LitemallOrder order) {
		litemallOrderMapper.updateByPrimaryKeySelective(order);
	}
	
	public int updataOrderPrintInfo(LitemallOrder record) {
		return litemallOrderMapper.updateByPrimaryKey(record);
	}
}
